package com.heima.media.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.heima.common.dto.PageResponseResult;
import com.heima.common.dto.ResponseResult;
import com.heima.common.dto.User;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.enums.MediaEnum;
import com.heima.common.util.UserThreadLocalUtil;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.dto.WmNewsDto;
import com.heima.media.dto.WmNewsPageDto;
import com.heima.media.entity.WmNews;
import com.heima.media.entity.WmNewsMaterial;
import com.heima.media.mapper.WmNewsMapper;
import com.heima.media.service.IAuditService;
import com.heima.media.service.IWmNewsMaterialService;
import com.heima.media.service.IWmNewsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import io.swagger.models.auth.In;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 自媒体图文内容信息表 服务实现类
 * </p>
 *
 * @author itheima
 * @since 2022-01-15
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements IWmNewsService {

    @Autowired
    private IWmNewsMaterialService newsMaterialService;


    @Autowired
    @Lazy
    private IAuditService auditService;


    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;


    /**
     * 文章上下架话题
     */
    @Value("${topic.upDownTopic}")
    private String upDownTopic;


    /**
     * 根据条件分页查询自媒体文章列表
     *
     * @param dto 入参查询条件dto对象
     * @return 自媒体文章列表
     */
    @Override
    public ResponseResult listByCondition(WmNewsPageDto dto) {
        User user = UserThreadLocalUtil.get();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //1.封装查询条件
        LambdaQueryWrapper<WmNews> queryWrapper = new LambdaQueryWrapper<>();
        //1.1 查询当前登录用户 自媒体用户ID
        queryWrapper.eq(WmNews::getUserId, user.getUserId());
        //1.2 设置排序
        queryWrapper.orderByDesc(WmNews::getCreatedTime);
        //1.3 文章状态
        if (dto.getStatus() != null) {
            queryWrapper.eq(WmNews::getStatus, dto.getStatus());
        }
        //1.4 日期查询
        if (dto.getBeginPubDate() != null) {
            queryWrapper.gt(WmNews::getPublishTime, dto.getBeginPubDate());
        }
        if (dto.getEndPubDate() != null) {
            queryWrapper.lt(WmNews::getPublishTime, dto.getEndPubDate());
        }
        //1.5 频道
        if (dto.getChannelId() != null) {
            queryWrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }
        //1.6 关键之模糊查询
        if (StringUtils.isNotBlank(dto.getKeyword())) {
            queryWrapper.like(WmNews::getTitle, dto.getKeyword());
        }
        //2.执行分页查询
        IPage<WmNews> page = this.page(new Page<>(dto.getPage(), dto.getSize()), queryWrapper);

        //3.封装相应结果
        return new PageResponseResult(dto.getPage(), dto.getSize(), page.getTotal(), page.getRecords());
    }


    /**
     * 自媒体用户提审（提交审核）文章
     *
     * @param dto 用户客户端填写各种信息
     * @return
     */
    @Override
    @GlobalTransactional
    public ResponseResult submit(WmNewsDto dto) {
        //1.验证用户是否登录
        User user = UserThreadLocalUtil.get();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //2.构建自媒体文章对象（提审），将入参中DTO属性拷贝到自媒体文章属性中，将自媒体提审文章保存
        WmNews wmNews = new WmNews();
        //2.1 将dto提交参数值复制给PO对象
        BeanUtils.copyProperties(dto, wmNews);
        wmNews.setUserId(user.getUserId());
        //2.2 设置文章封面
        List<ImageDto> images = dto.getImages();
        //2.2.0 从文章正文获取内容中图片集合
        List<ImageDto> contentImages = getImagesFromContent(dto.getContent());
        //2.2.1 判断用户选择封面：单图 或者 多图  dto参数中包含 images集合有值
        if (!CollectionUtils.isEmpty(images)) {
            //将提交来图片集合采用stream流处理，获取图片地址，多个图片地址采用逗号方分隔
            String imageListStr = images.stream().map(ImageDto::getUrl).collect(Collectors.joining(","));
            wmNews.setImages(imageListStr);
            //封面类型 前端提交
        } else if (CollectionUtils.isEmpty(images) && dto.getType().equals(MediaEnum.NEWS_COVER_TYPE_AUTO.getVal())) {
            //2.2.2 用户选择了自动 images集合为空 type为自动 从文章正文中获取图片资源作为文章封面
            //内容图片的个数小于等于2  则为单图截图一张图，内容图片大于等于3，则为多图，截图三张图，内容中没有图片，则为无图
            if (CollectionUtils.isEmpty(contentImages)) {
                //正文中没有图片 设置为无图
                wmNews.setType(MediaEnum.NEWS_COVER_TYPE_NONE.getVal());
            } else if (contentImages.size() < 3) {
                //获取内容中第一张图片作为封面
                ImageDto imageDto = contentImages.get(0);
                wmNews.setImages(imageDto.getUrl());
                wmNews.setType(MediaEnum.NEWS_COVER_TYPE_ONE.getVal());
            } else {
                //内容中图片数量大于3 截图前三张图片作为封面
                List<ImageDto> imageDtos = contentImages.subList(0, 3);
                String collect = imageDtos.stream().map(ImageDto::getUrl).collect(Collectors.joining(","));
                wmNews.setImages(collect);
                wmNews.setType(MediaEnum.NEWS_COVER_TYPE_MANY.getVal());
            }
        }
        //2.3 将自媒体提审文章进行保存
        this.save(wmNews);

        //3.将自媒体文章中 封面图片，内容中包含图片 跟文章进行关联 将关系存入自媒体文章素材关系表
        if (!dto.getStatus().equals(MediaEnum.NEWS_SUBMIT_STATUS_DRAFT.getVal())) {
            //如果用户操作不是保存草稿
            //3.1 设置文章跟 封面素材关系
            List<ImageDto> converImageList = dto.getImages();
            saveArticleMaterialRelation(converImageList, MediaEnum.MATERIAL_TYPE_REF_TYPE_CONVERIMG.getVal(), wmNews.getId());
            //3.2 设置文章 跟 正文中素材关系
            saveArticleMaterialRelation(contentImages, MediaEnum.MATERIAL_TYPE_REF_TYPE_CONTENTIMG.getVal(), wmNews.getId());
        }

        //TODO 指定送审（提交审核）业务
        auditService.audit(wmNews.getId());
        return ResponseResult.okResult();
    }

    /**
     * 将文章跟素材建立关联
     *
     * @param imageDtoList
     * @param type         0：内容引入  1：封面引用
     * @param newsId       文章ID
     */
    private void saveArticleMaterialRelation(List<ImageDto> imageDtoList, Integer type, Integer newsId) {
        int ord = 0;
        if (!CollectionUtils.isEmpty(imageDtoList)) {
            for (ImageDto imageDto : imageDtoList) {
                WmNewsMaterial wmNewsMaterial = new WmNewsMaterial();
                wmNewsMaterial.setMaterialId(imageDto.getId());
                wmNewsMaterial.setNewsId(newsId);
                wmNewsMaterial.setType(type);
                wmNewsMaterial.setOrd(ord++);
                newsMaterialService.save(wmNewsMaterial);
            }
        }
    }


    /**
     * 从提交内容中获取图片
     *
     * @param content
     * @return
     */
    private List<ImageDto> getImagesFromContent(String content) {
        //1.将提交内容字符串转为JSON数组
        List<ContentDto> contentDtoList = JSONObject.parseArray(content, ContentDto.class);
        //2.遍历数组将type为image对象获取到

        List<ImageDto> contentDtos = new ArrayList<>();
        for (ContentDto contentDto : contentDtoList) {
            if ("image".equals(contentDto.getType())) {
                ImageDto imageDto = new ImageDto();
                imageDto.setId(contentDto.getId());
                imageDto.setUrl(contentDto.getValue());
                contentDtos.add(imageDto);

            }
        }
        return contentDtos;
    }


    /**
     * 文章上下架
     * 生产者：发送消息到kafka
     *
     * @param dto 文章ID 上下架状态
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //1.根据自媒体文章ID 查询自媒体文章信息
        WmNews wmNews = this.getById(dto.getId());
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //2.判断自媒体文章状态：只有审核通过发布后文章才能被下架
        if (!wmNews.getStatus().equals(MediaEnum.NEWS_SUBMIT_STATUS_PUBLISH.getVal())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_CAN_NOT_UPDATE);
        }

        //3.修改自媒体文章上下架状态
        wmNews.setEnable(dto.getEnable() == 0 ? false : true);
        this.updateById(wmNews);

        //4.发送消息到kafka  通知文章微服务（更新）更新发布文章状态
        //消息数据自媒体文章ID，上下架状态
        HashMap<String, Object> map = new HashMap<>();
        map.put("articleId", wmNews.getArticleId());
        map.put("isDown", dto.getEnable() == 1 ? false : true);
        String message = JSON.toJSONString(map);
        kafkaTemplate.send(upDownTopic, message);
        return ResponseResult.okResult();
    }

}
